home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / dos / communic / pcmail / main / desk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  12.6 KB  |  429 lines

  1. /*++
  2. /* NAME
  3. /*    desk 3
  4. /* CATEGORY
  5. /*    mail box display
  6. /* PROJECT
  7. /*    pc-mail
  8. /* PACKAGE
  9. /*    mail
  10. /* SYNOPSIS
  11. /*    #include "mail.h"
  12. /*
  13. /*    void init()
  14. /*
  15. /*    int junk_desk()
  16. /*
  17. /*    char message[];
  18. /*    char comment[];
  19. /* DESCRIPTION
  20. /*      Most functions in this module are invoked by the keyboard interpreter
  21. /*      and are responsible for the mail box view of message summary lines.
  22. /*
  23. /*    init() is the main entry point. It presents the user with a display
  24. /*    of message categories (create, unread, already seen, unsent, sent,
  25. /*    in preparation), and the number of messages in each category. After 
  26. /*    the user has chosen a category, an editor is invoked, or a sorted 
  27. /*    display of all messages in the respective category is displayed.
  28. /*
  29. /*    junk_desk() should be invoked when the number of files in the mail box
  30. /*    may have changed. Always returns a zero value. This function
  31. /*    should be called when a message is added to, or deleted from, the
  32. /*    spool directory.
  33. /*
  34. /*    The strings "message" and "comment" hold path names of the currently
  35. /*    selected message file, and its associated meta file (with message
  36. /*    destination, origin or comments). These names are used by functions
  37. /*    that read, delete or otherwise manipulate message files.
  38. /* FILES
  39. /*      mail header files in the spool directory
  40. /* SEE ALSO
  41. /*      pager(3), pager(5), kbdinp(3)
  42. /* DIAGNOSTICS
  43. /*      If a selected mail message could not be found an error message
  44. /*      is displayed instead.
  45. /* BUGS
  46. /*      Since a message can be accessed only if its metafile exists,
  47. /*    a message is "lost" when for some reason the metafile is
  48. /*    not available.
  49. /* AUTHOR(S)
  50. /*      W.Z. Venema
  51. /*      Eindhoven University of Technology
  52. /*      Department of Mathematics and Computer Science
  53. /*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  54. /* CREATION DATE
  55. /*    Tue May 12 15:35:20 GMT+1:00 1987
  56. /* LAST MODIFICATION
  57. /*    90/01/22 13:01:29
  58. /* VERSION/RELEASE
  59. /*    2.1
  60. /*--*/
  61.  
  62. #include <stdio.h>
  63. #include <ctype.h>
  64. #include <errno.h>
  65. #include <sys/types.h>
  66. #include <sys/stat.h>
  67. #include <time.h>
  68.  
  69. #include "defs.h"
  70. #include "mail.h"
  71. #include "path.h"
  72. #include "ndir.h"
  73. #include "pager.h"
  74. #include "screen.h"
  75. #include "status.h"
  76. #include "window.h"
  77. #include "ascf.h"
  78. #include "snapshot.h"
  79.  
  80. hidden void make_desk();        /* forward declarations */
  81. hidden int pick_desk();
  82. hidden int show_desk();
  83. hidden void desk();
  84. hidden void make_init();
  85. hidden int pick_init();
  86. hidden int show_init();
  87. hidden char *singular();
  88.  
  89. hidden File *deskfile = 0;        /* mail box pager file */
  90. hidden File *initfile = 0;        /* initial screen */
  91. public char message[BUFSIZ];        /* path to message file */
  92. public char comment[BUFSIZ];        /* path to meta file */
  93.  
  94. /* Definitions of the various message categories */
  95.  
  96. typedef struct {
  97.     char   *type;            /* work, incoming, outgoing, ... */
  98.     char    mesg;            /* message-file prefix */
  99.     char    meta;            /* meta-file prefix */
  100.     int   (*access) ();            /* message access function */
  101.     int     flags;            /* see below */
  102.     char   *whatsit;            /* explanation */
  103. } CATEGORY;
  104.  
  105. #define    MULT    1            /* multi-message category */
  106. #define    DMON    2            /* subject to daemon activity */
  107.  
  108. hidden CATEGORY categories[] = {
  109.     "Create", WORK_MESG, WORK_META, create,0,       "Create a new message",
  110.     "Work",   WORK_MESG, WORK_META, work, MULT,     "Message%S in preparation",
  111.     "New",    NEW_MESG,  NEW_META,  mbox, MULT|DMON,"Unread message%S",
  112.     "In",     OLD_MESG,  OLD_META,  mbox, MULT,     "Message%S already read",
  113.     "Out",    OUT_MESG,  OUT_META,  mbox, MULT|DMON,"Message%S not-yet sent",
  114.     "Sent",   SENT_MESG, SENT_META, mbox, MULT|DMON,"Message%S already sent",
  115.     0,                    /* terminator */
  116. };
  117.  
  118. hidden CATEGORY *category;        /* selected message category */
  119.  
  120. /* table with all meta-file name prefixes */
  121.  
  122. hidden char metalist[] = {
  123.     WORK_META, NEW_META, OLD_META, OUT_META, SENT_META, 0,
  124. };
  125.  
  126. hidden char initsingle[] = "%-6s %5s %s";
  127. hidden char initmulti[] = "%-6s %5u %s";
  128. hidden char scanmulti[] = "%s %u";
  129.  
  130. hidden char dispfmt[] = "%5u  %.16s  %.53s";
  131. hidden char dispfmts[] = "%5u  %.16s  %.40s \"%s\"";
  132. hidden char scanfmt[] = "%u";
  133.  
  134. /* init - main entry point for message manipulations */
  135.  
  136. public void init()
  137. {
  138.     static Screen screen[] = {
  139.     'C',    "Close",    0,    "Terminate the program",
  140.     'F',    "File",        file,    "Mail a copy of an ordinary file",
  141. #ifndef    DAEMON
  142.     'N',    "Network",    call,    "Exchange mail with the network",
  143. #endif
  144.     'S',    "Setup",    setup,    "Set communications parameters",
  145.     'A',    "Alias",    alias,    "Display the alias data base",
  146.     'P',    "Print",    print,    "Print contents of this display",
  147.     UP,    "Up",        up_pager,    csrup,
  148.     DOWN,    "Down",        dn_pager,    csrdn,
  149.     ENTER,    "Enter",    pick_init,    "Select message category",
  150.     0,    0,        show_init,
  151.     "Select a message category with cursor keys and press ENTER\n\
  152. or select one of the commands in the top line."
  153.     };
  154.  
  155.     kbdinp(screen);                /* and there they go... */
  156. }
  157.  
  158. /* show_init - create or refresh the initial screen */
  159.  
  160. hidden int show_init()
  161. {
  162.     if (initfile == 0) {            /* no initial screen file */
  163.     patience();                /* one moment please */
  164.     make_init(initfile = open_pager());    /* build initial screen */
  165.     } else {                    /* pager file exists */
  166.     set_pager(initfile);            /* select pager file */
  167.     }
  168.     ds_pager();                    /* display it */
  169.     return (0);                    /* screen is ok */
  170. }
  171.  
  172. /* junk_init - force re-scan of mail directory and re-build of initial screen */
  173.  
  174. hidden void junk_init()
  175. {
  176.     if (initfile) {
  177.     close_pager(initfile);
  178.     initfile = 0;
  179.     }
  180.     snap_junk();                /* re-scan mail directory */
  181. }
  182.  
  183. /* make_init - build initial screen */
  184.  
  185. hidden void make_init(pp)
  186. File   *pp;
  187. {
  188.     register SNAP_SHOT *s;
  189.     register unsigned count;
  190.     register CATEGORY *c;
  191.  
  192.     /*
  193.      * In case of multi-message categories, show the number of messages in
  194.      * that category.
  195.      */
  196.  
  197.     for (c = categories; c->type; c++) {
  198.     if (c->flags & MULT) {            /* multi-message category */
  199.         for (count = 0, s = snap_shot(metalist); s->prefix; s++)
  200.         if (c->meta == s->prefix)
  201.             count++;
  202.         app_pager(pp, strcons(initmulti, c->type, count,
  203.                   singular(count, c->whatsit)));
  204.     } else {                /* single-message category */
  205.         app_pager(pp, strcons(initsingle, c->type, "", c->whatsit));
  206.     }
  207.     }
  208.     pp->opts |= PG_NOEND;            /* suppress 'end-of-display' */
  209. }
  210.  
  211. /* exec_msg - execute access function for a particular message */
  212.  
  213. hidden int exec_msg(msgno)
  214. unsigned msgno;
  215. {
  216.     (void) strcpy(message, mesg_file(category->mesg, msgno));
  217.     (void) strcpy(comment, meta_file(category->meta, msgno));
  218.     return (CALL(category->access) (category->meta, msgno));
  219. }
  220.  
  221. /* pick_init - user selected a message category */
  222.  
  223. hidden int pick_init()
  224. {
  225.     char    type[BUFSIZ];
  226.     register CATEGORY *c;
  227.     unsigned count;
  228.  
  229.     /*
  230.      * Read the message type (in, out, work etc) from the summary line in the
  231.      * initial display.
  232.      * 
  233.      * On systems that do not use daemons for message delivery, disallow
  234.      * selection an empty message category.
  235.      */
  236.  
  237.     count = type[0] = 0;            /* initialize */
  238.     (void) sscanf(gets_pager(), scanmulti, type, &count);
  239.  
  240.     for (c = categories; c->type; c++) {    /* try to recognize the */
  241.     if (strcmp(c->type, type) == 0) {    /* message type */
  242.         category = c;            /* GLOBAL! */
  243.         if ((c->flags & MULT) == 0) {    /* create-message category */
  244.         return (exec_msg(newseqno()));
  245. #ifndef DAEMON
  246.         } else if (count == 0) {        /* multi-message, empty */
  247.         break;
  248. #endif
  249.         } else {                /* multi-message */
  250.         desk();
  251.         return (S_REDRAW);
  252.         }
  253.     }
  254.     }
  255.     beep();                    /* error */
  256.     return (0);                    /* nothing happened */
  257. }
  258.  
  259. /* desk - manipulate one category of messages */
  260.  
  261. hidden void desk()
  262. {
  263.     static Screen screen[] = {
  264.     'C',    "Close",    0,    initscreen,
  265.     'F',    "File",        file,    "Mail a copy of an ordinary file",
  266. #ifndef    DAEMON
  267.     'N',    "Network",    call,    "Exchange mail with the network",
  268. #endif
  269.     'S',    "Setup",    setup,    "Set communications parameters",
  270.     'A',    "Alias",    alias,    "Display the alias data base",
  271.     'P',    "Print",    print,    "Print contents of this display",
  272.     PGUP,    PgUp,        pu_pager,pageup,
  273.     PGDN,    PgDn,        pd_pager,pagedn,
  274.     UP,    "Up",        up_pager,csrup,
  275.     DOWN,    "Down",        dn_pager,csrdn,
  276.     ENTER,    "Enter",    pick_desk,"Select message",
  277.     0,    0,        show_desk,
  278.     "Select a message with the cursor keys and press ENTER\n\
  279. or select one of the commands in the top line."
  280.     };
  281.  
  282.     /* 
  283.      * On systems where daemon processes take care of message delivery, we
  284.      * re-scan the mail directory if the user selects a message category that
  285.      * can be affected by daemon activity, and force a re-scan of the mail
  286.      * directory upon return to the initial screen (unless that just happened
  287.      * as a result of some user action).
  288.      */
  289.  
  290. #ifdef    DAEMON
  291.     if (category->flags & DMON)            /* if affected by daemons */
  292.     junk_init();                /* re-scan mail directory */
  293. #endif
  294.     kbdinp(screen);
  295. #ifdef    DAEMON
  296.     junk_init();                /* re-scan mail directory */
  297. #endif
  298.     close_pager(deskfile);
  299.     deskfile = 0;
  300. }
  301.  
  302. /* show_desk - create or refresh a display of a mail box selection */
  303.  
  304. hidden int show_desk()
  305. {
  306.     if (deskfile == 0) {            /* no mail box pager file */
  307.     patience();            /* one moment please... */
  308.     make_desk(deskfile = open_pager());    /* build mail box display */
  309.     } else {                    /* pager file exists */
  310.     set_pager(deskfile);            /* select pager file */
  311.     }
  312.     ds_pager();                    /* display it */
  313.     return (0);                    /* screen is ok */
  314. }
  315.  
  316. /* make_desk - build display of summary lines of selected message type */
  317.  
  318. hidden void make_desk(pp)
  319. File   *pp;
  320. {
  321.     FILE   *fp;                /* used to read meta info */
  322.     char    ident[MAXLINE];        /* usually person\'s name or address */
  323.     char    subj[MAXLINE];        /* subject info */
  324.     char   *line;
  325.     register SNAP_SHOT *s;        /* snapshot table */
  326.     struct stat st;
  327.  
  328.     /*
  329.      * The message sequence number and type are already known; we just have
  330.      * to retrieve from the meta file: a person\'s name or address (first
  331.      * line) and an optional subject (second line).
  332.      * 
  333.      * If Subject: information is present we truncate the person\'s name or
  334.      * address to (screen width - 40) columns. Any text that extends beyond
  335.      * the width of the screen is truncated as well.
  336.      */
  337.  
  338.     for (s = snap_shot(metalist); s->prefix; s++) {
  339.     if ((s->prefix == category->meta)
  340.     && (fp = ascopen(meta_file(s->prefix, s->msgno), "r"))) {
  341.         if ((ascgets(ident, sizeof(ident), fp) != 0)
  342.         && (fstat(fileno(fp), &st) == 0)) {
  343.         if (ascgets(subj, sizeof(subj), fp) && subj[0]) {
  344.             /* subject found; truncate person\'s name or address */
  345.             if (strlen(ident) > CO - 40)
  346.             (void) strcpy(ident + CO - 42, "..");
  347.             line = strcons(dispfmts, s->msgno,
  348.                    tstamp(&(st.st_mtime)), ident, subj);
  349.         } else {
  350.             /* no subject info */
  351.             line = strcons(dispfmt, s->msgno,
  352.                    tstamp(&(st.st_mtime)), ident);
  353.         }
  354.         /* truncate final result anyway */ if (strlen(line) >= CO - 1)
  355.             (void) strcpy(line + CO - 3, "..");
  356.         app_pager(pp, line);
  357.         }
  358.         ascclose(fp);
  359.     }
  360.     }
  361.  
  362. /* sort summary lines in reverse order, i.e. newest comes first */
  363.  
  364.     sort_pager(pp, BACK_SORT);
  365. }
  366.  
  367. /* pick_desk - user selected a message */
  368.  
  369. hidden int pick_desk()
  370. {
  371.     unsigned msgno;
  372.  
  373.     /*
  374.      * Read message sequence number from summary line in the mail box
  375.      * display. Build actual message file and meta file names. Then call the
  376.      * appropriate function to access that message.
  377.      */
  378.  
  379.     msgno = 0;                    /* initialize */
  380.     (void) sscanf(gets_pager(), scanfmt, &msgno);
  381.  
  382.     if (msgno) {
  383.     return (exec_msg(msgno));
  384.     } else {
  385.     beep();                    /* unrecognized message id */
  386.     return (0);                /* nothing happened */
  387.     }
  388. }
  389.  
  390. /* junk_desk - force rebuilding of mail box display */
  391.  
  392. public int junk_desk()
  393. {
  394.     if (deskfile) {
  395.     close_pager(deskfile);        /* delete pager file */
  396.     deskfile = 0;                /* say it's gone */
  397.     }
  398.     junk_init();                /* and re-scan mail directory */
  399.     return (0);                    /* in case one wants it */
  400. }
  401.  
  402. /* singular - replace %S depending on whether a count is 1 */
  403.  
  404. hidden char *singular(c, s)
  405. int     c;
  406. register char *s;
  407. {
  408.     static char buf[BUFSIZ];
  409.     register char *bp = buf;
  410.  
  411.     while (*s) {
  412.     if (*s == '%') {
  413.         if (s[1] == 'S') {            /* expand %S */
  414.         if (c != 1)
  415.             *bp++ = 's';
  416.         s += 2;
  417.         } else if (s[1] == '\0') {        /* don\'t fall off end */
  418.         *bp++ = *s++;
  419.         } else {                /* leave %<any> alone */
  420.         *bp++ = *s++, *bp++ = *s++;
  421.         }
  422.     } else {
  423.         *bp++ = *s++;
  424.     }
  425.     }
  426.     *bp = '\0';
  427.     return (buf);
  428. }
  429.